#include <vector>
#include <unordered_map>
#include <sstream>
#include <ostream>
#include <cstring>
#include <iostream>

namespace ym
{
    class Json
    {
        friend std::ostream &operator<<(std::ostream &os, const Json &json);

    public:
        typedef std::vector<Json *> Array;
        typedef std::unordered_map<std::string, Json *> Object;

    public:
        enum JsonType
        {
            json_null,
            json_bool,
            json_int,
            json_double,
            json_string,
            json_array,
            json_object
        };

    private:
        union Value
        {
        public:
            bool val_bool;
            int val_int;
            float val_double;
            std::string *val_string;
            Array *val_array;
            Object *val_object;
        };
        JsonType jsonType;
        Value value;
        static size_t alive_count;

    public:
        __declspec(dllexport) Json();
        __declspec(dllexport) Json(bool val);
        __declspec(dllexport) Json(int val);
        __declspec(dllexport) Json(double val);
        __declspec(dllexport) Json(const std::string &val);
        __declspec(dllexport) Json(Array *val);
        __declspec(dllexport) Json(Object *val);
        __declspec(dllexport) ~Json();
        __declspec(dllexport) int getInt();
        __declspec(dllexport) double getDouble();
        __declspec(dllexport) bool getBool();
        __declspec(dllexport) const std::string &getString();
        __declspec(dllexport) const Array &getArray();
        __declspec(dllexport) const Object &getObject();
        __declspec(dllexport) bool isBoolean();
        __declspec(dllexport) bool isNull();
        __declspec(dllexport) bool isInt();
        __declspec(dllexport) bool isDouble();
        __declspec(dllexport) bool isString();
        __declspec(dllexport) bool isArray();
        __declspec(dllexport) bool isObject();
        __declspec(dllexport) bool isEmpty();
        __declspec(dllexport) bool hasKey(const std::string &key);
        __declspec(dllexport) Json *get(int index);
        __declspec(dllexport) Json *get(const std::string &key);
        __declspec(dllexport) std::string toString();
        __declspec(dllexport) const char *getTypeName();
    };
    __declspec(dllexport) std::ostream &operator<<(std::ostream &os, const Json &json);
}